package main

import (
	"aimemo/config"            // 导入数据库配置包，用于初始化数据库连接
	"aimemo/model"             // 导入数据模型包，包含任务结构体定义
	"aimemo/service"           // 导入AI服务包，用于调用百度千帆API生成规划和建议
	"github.com/gin-gonic/gin" // 导入Gin框架，用于构建HTTP服务和路由
	"net/http"                 // 导入HTTP包，用于定义HTTP状态码
	"strconv"                  // 导入字符串转换包，用于字符串与整数的转换
	"time"                     // 导入时间包，用于时间格式处理
)

// main函数是程序的入口点，负责初始化服务、配置路由并启动HTTP服务
func main() {
	// 1. 初始化数据库连接
	// 调用config包的InitDB函数，建立与MySQL的连接并自动迁移数据表结构
	if err := config.InitDB(); err != nil {
		// 若数据库初始化失败（如连接错误、迁移失败），则终止程序并打印错误信息
		// panic会触发程序退出，适合初始化阶段的致命错误
		panic("数据库初始化失败：" + err.Error())
	}

	// 2. 初始化Gin引擎
	// gin.Default()会创建一个默认的Gin实例，包含两个默认中间件：
	// - Logger：记录请求日志（方法、路径、状态码、耗时等）
	// - Recovery：捕获程序 panic 并返回500错误，避免服务崩溃
	r := gin.Default()

	// 3. 配置模板和静态资源
	// 加载templates目录下的所有HTML模板文件（支持通配符*）
	// 后续可通过c.HTML()渲染这些模板，并传递数据
	r.LoadHTMLGlob("templates/*")
	// 将/static路径映射到本地的./static目录
	// 前端页面中通过/src="/static/css/style.css"即可访问静态资源
	r.Static("/static", "./static")

	// 4. 定义路由规则（HTTP方法 + 路径 + 处理函数）
	// 4.1 首页路由：处理GET请求，展示所有任务列表
	r.GET("/", func(c *gin.Context) {
		// 声明一个任务切片，用于存储从数据库查询的结果
		var tasks []model.Task

		// 从数据库查询所有任务：
		// - config.DB是全局数据库连接实例
		// - Order("created_at desc")：按创建时间倒序排序（最新的任务在前面）
		// - Find(&tasks)：将查询结果存入tasks切片
		config.DB.Order("created_at desc").Find(&tasks)

		// 渲染templates/index.html模板，并传递数据到前端
		// gin.H{"tasks": tasks} 是一个map，前端可通过{{.tasks}}访问任务列表
		c.HTML(http.StatusOK, "index.html", gin.H{"tasks": tasks})
	})

	// 4.2 添加任务路由：处理POST请求，接收前端表单并创建任务
	r.POST("/task/add", func(c *gin.Context) {
		// 1. 从前端表单中获取参数（对应HTML中input/textarea的name属性）
		title := c.PostForm("title")         // 任务标题（必填）
		content := c.PostForm("content")     // 任务详情（可选）
		dueTimeStr := c.PostForm("due_time") // 截止时间（前端格式为"2024-12-31T23:59"）

		// 2. 转换截止时间格式：前端传的是"T"分隔的字符串，需转为Go的time.Time类型
		// 参考时间"2006-01-02T15:04"是Go的特殊日期格式（固定写法，代表年-月-日T时:分）
		dueTime, err := time.Parse("2006-01-02T15:04", dueTimeStr)
		if err != nil {
			// 若格式转换失败（如前端传错格式），返回400错误和提示信息
			c.JSON(http.StatusBadRequest, gin.H{"msg": "截止时间格式错误，请使用正确格式"})
			return // 终止当前处理函数，避免后续代码执行
		}

		// 3. 调用AI服务生成任务规划和建议
		// 传给AI的时间格式转为"2006-01-02 15:04"（空格分隔，更符合人类阅读习惯）
		aiPlan, aiAdvice, err := service.GetAIAdvice(
			title,
			content,
			dueTime.Format("2006-01-02 15:04"),
		)
		if err != nil {
			// 若AI调用失败（如网络问题、API密钥错误），返回500错误
			c.JSON(http.StatusInternalServerError, gin.H{"msg": "AI调用失败：" + err.Error()})
			return
		}

		// 4. 创建任务记录并保存到数据库
		task := model.Task{
			Title:    title,               // 任务标题
			Content:  content,             // 任务详情
			DueTime:  dueTime,             // 截止时间（time.Time类型）
			AIPlan:   aiPlan,              // AI生成的规划
			AIAdvice: aiAdvice,            // AI生成的建议
			Status:   model.StatusPending, // 初始状态为"待执行"
		}
		// 调用Gorm的Create方法将任务插入数据库
		config.DB.Create(&task)

		// 5. 返回成功响应给前端（JSON格式）
		c.JSON(http.StatusOK, gin.H{"msg": "任务添加成功（AI规划已生成）"})
	})

	// 4.3 更新任务状态路由：处理POST请求，修改任务的执行状态
	r.POST("/task/status", func(c *gin.Context) {
		// 1. 接收前端传递的任务ID和新状态
		idStr := c.PostForm("id") // 任务ID（前端传字符串，需转为int）
		// 将字符串ID转为int类型（数据库中ID是int类型）
		id, err := strconv.Atoi(idStr)
		if err != nil {
			// 若转换失败（如ID不是数字），返回400错误
			c.JSON(http.StatusBadRequest, gin.H{"msg": "任务ID格式错误，必须是数字"})
			return
		}

		// 将前端传递的状态字符串转为model.TaskStatus类型（确保符合枚举值）
		newStatus := model.TaskStatus(c.PostForm("status"))

		// 2. 更新数据库中对应任务的状态
		// - Model(&model.Task{})：指定操作的模型
		// - Where("id = ?", id)：条件：只更新ID为指定值的任务
		// - Update("status", newStatus)：将status字段更新为新状态
		config.DB.Model(&model.Task{}).Where("id = ?", id).Update("status", newStatus)

		// 3. 返回成功响应
		c.JSON(http.StatusOK, gin.H{"msg": "任务状态更新成功"})
	})

	// 5. 启动HTTP服务，监听8080端口
	// 服务启动后，可通过http://localhost:8080访问
	err := r.Run(":8080")
	if err != nil {
		// 若启动失败（如端口被占用），则返回（程序终止）
		return
	}
}
